package com.game.logic.map;

import com.coment.cfg.luban.Tables;
import com.coment.cfg.luban.constant.AIDCFG;
import com.coment.cfg.luban.pvp.PVPMapCfg;
import com.coment.game.config.ConfigException;
import com.game.dao.core.GameDao;
import com.game.dao.user.roles.RolesDao;
import com.game.framework.SpringManager;
import com.game.logic.fighting.pve.GameServiceImpl;
import com.xs.action.exection.ActionException;
import com.xs.build.server.websocket.channel.ClientManager;
import com.xs.build.server.websocket.channel.PushGroup;
import lombok.*;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class WordMap {
    public static void leave(Integer anchorInfoId) {
        if (mapEntryMap.containsKey(anchorInfoId)) {
            MapEntryInfo mapEntryInfo = mapEntryMap.get(anchorInfoId);
            mapEntryMap.remove(anchorInfoId);
            leaveThePlot(anchorInfoId, mapEntryInfo);
            // 推送
            ClientManager.sendMessageToClient(PushGroup.GAME_GROUP, wordItemMap, TAG);
        }
    }

    /// 校验是否在地图中
    public static boolean check(Integer anchorInfoId) {
        return mapEntryMap.containsKey(anchorInfoId);
    }

    public static class WordItemMap extends ConcurrentHashMap<Integer, MapItem> {}
    /// 地图 K:mapId , V:MapItem
    public static final WordItemMap wordItemMap = new WordItemMap();
    /// 地图实体数据 k:anchorInfoId , v:mapEntryInfo
    public static final Map<Integer, MapEntryInfo> mapEntryMap = new ConcurrentHashMap<>();


    private static final GameDao gameDao = SpringManager.getInstance().getBean(GameDao.class);
    private static final GameServiceImpl gameServiceImpl = SpringManager.getInstance().getBean(GameServiceImpl.class);
    private static final RolesDao rolesDao = SpringManager.getInstance().getBean(RolesDao.class);

    public static final String TAG = "PVE_MAP";

    /// 加入地图并入座
    @Synchronized
    public static void joinMap(Integer anchorInfoId, Integer mapId , Integer level, String chanelId, String maxLevelRolesId) {
        ClientManager.joinTag(PushGroup.GAME_GROUP, chanelId, TAG);

        if (mapId != null) {
            /// 查看实体信息
            MapEntryInfo mapEntryInfo = mapEntryMap.getOrDefault(anchorInfoId, new MapEntryInfo(mapId, anchorInfoId, chanelId));

            /// 加入前校验
            toSeatCheck(mapId, maxLevelRolesId);

            /// 离开旧地块
            if (!Objects.equals(mapEntryInfo.getMapId(), mapId)) leaveThePlot(anchorInfoId, mapEntryInfo);

            /// 加入新地块
            MapItem mapItem = wordItemMap.computeIfAbsent(mapId, k -> new MapItem(mapId));
            mapItem.entrySet.add(anchorInfoId);


            /// 更新实体信息
            mapEntryInfo.setMapId(mapId);
            mapEntryMap.put(anchorInfoId, mapEntryInfo); // 使用 anchorInfoId 作为键

            find(anchorInfoId, level);
        }
        ClientManager.sendMessageToClient(PushGroup.GAME_GROUP, wordItemMap, TAG);
    }

    /// 寻宝
    private static void find(Integer anchorInfoId, Integer level) {
        // 是否入座
        gameServiceImpl.clear(anchorInfoId);

        MapEntryInfo mapEntryInfo = mapEntryMap.get(anchorInfoId);
        if (mapEntryInfo == null) {
            throw new ActionException("请先加入地图");
        }

        PVPMapCfg mapCfg = Tables.cfg.get_tbpvpmapcfg().get(mapEntryInfo.getMapId());
        if (level < mapCfg.StarID || level > mapCfg.EndID) throw new ActionException("请选择正确的关卡");

        if (Optional.ofNullable(Tables.cfg.get_tblevelconfig().get(level)).isEmpty()) {
            level = -99;
        }

        gameServiceImpl.initializeGame(anchorInfoId, level);
    }


    private static void toSeatCheck(Integer mapId, String maxLevelRolesId) {
        Optional<PVPMapCfg> mapCfg = Optional.ofNullable(Tables.cfg.get_tbpvpmapcfg().get(mapId));
        if (mapCfg.isEmpty()) {
            throw new ConfigException("没有此地图");
        }
        PVPMapCfg pvpMapCfg = mapCfg.get();

        // 读表 配置对应的地图id  TODO
        // 是否是开放时间
        boolean isOpen = true;
        if (!isOpen) {
            throw new RuntimeException("地图未开放");
        }

        // 人数限制配置表读取
        MapItem mapItem = wordItemMap.computeIfAbsent(mapId, k -> new MapItem(mapId));
        int limitNum = pvpMapCfg.AnchorNum;
        boolean isLimit = mapItem.entrySet.size() < limitNum;
        if (!isLimit) {
            throw new RuntimeException("地图已满");
        }


        // 等级限制
        int mapClass = pvpMapCfg.MapClass;
        if (mapClass != 0) {
            // 获取玩家等级
            int playerLevel = rolesDao.findByIdMust(maxLevelRolesId).getRolePanel().getCultivatePanel().getBase().get(AIDCFG.level).intValue();
            boolean isLevelLimit = playerLevel >= mapClass;
            if (!isLevelLimit) {
                throw new RuntimeException("等级不够");
            }
        }
    }

    private static void leaveThePlot(Integer anchorInfoId, MapEntryInfo mapEntryInfo) {
        Integer mapId = mapEntryInfo.getMapId();
        leaveThePlot(anchorInfoId, mapId);
    }

    private static void leaveThePlot(Integer anchorInfoId, Integer mapId) {
        MapItem oldMapItem = wordItemMap.get(mapId);
        if (oldMapItem != null) {
            oldMapItem.entrySet.remove(anchorInfoId);
            // 如果旧地块为空，可以考虑移除该地块
            if (oldMapItem.entrySet.isEmpty()) {
                wordItemMap.remove(mapId);
            }
        }
    }



    @Data
    @EqualsAndHashCode(of = "id")
    @AllArgsConstructor
    @NoArgsConstructor
    public static class MapItem {
        /// 地图id
        public Integer id;

        /// 地块实体
        public Set<Integer> entrySet;

        public MapItem(int mapId) {
            this.id = mapId;
            this.entrySet = new HashSet<>();
        }
    }


    @Data
    @EqualsAndHashCode(of = "anchorInfoId")
    @AllArgsConstructor
    @NoArgsConstructor
    public static class MapEntryInfo {
        /// 主播id
        Integer anchorInfoId;

        /// 通信id
        String chanelId;

        /// 地图id
        public Integer mapId;

        public MapEntryInfo(int mapId, Integer anchorInfoId, String chanelId) {
            this.mapId = mapId;
            this.anchorInfoId = anchorInfoId;
            this.chanelId = chanelId;
        }
    }
}
